﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using GrayParrot.Core.ServiceBus;
using GrayParrot.RabbitMQ.Configuration;
using GrayParrot.Scheduling;
using RabbitMQ.Client;

namespace GrayParrot.RabbitMQ
{
    /// <summary>
    /// Publisher class for RabbitMQ Service Bus...
    /// </summary>
    /// <seealso cref="System.IDisposable" />
    public class Publisher<T> : IDisposable, IPublisher<T, byte[]>
        where T : class, new()
    {
        private bool _disposed;

        private string Endpoint { get; set; }
        private string Exchange { get; set; }
        private string RoutingKey { get; set; }

        IModel m_model = null;

        /// <summary>
        /// Initializes a new instance of the <see cref="Publisher"/> class.
        /// </summary>
        public Publisher()
        {

        }

        public Publisher(Subscription settings)
        {
            Endpoint = settings.ConnectionString;
            Exchange = settings.Exchange;
            RoutingKey = settings.RoutingKey;

            Init();
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Publisher"/> class.
        /// </summary>
        /// <param name="endpoint">The endpoint.</param>
        /// <param name="topic">The topic.</param>
        public Publisher(string exchange, string queue)
        {
            //Endpoint = endpoint

            Init();
        }

        /// <summary>
        /// Initializes this instance.
        /// </summary>
        private void Init()
        {
            RabbitMQService m_service = new RabbitMQService();
            m_service.GetRabbitMQConnection(Endpoint);
            m_model = m_service.GetRabbitMQModel();
        }

        /// <summary>
        /// Sends the specified message.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <returns></returns>
        public bool Send(MessageBusBase<T, byte[]> message)
        {
            bool retValue = false;

            try
            {
                if (m_model != null)
                {
                    IBasicProperties props = m_model.CreateBasicProperties();
                    props.ContentType = "application/octet-stream";
                    props.DeliveryMode = 2;

                    byte[] m_body = message.ToMessage();
                    m_model.BasicPublish(Exchange, RoutingKey, props, m_body);

                    retValue = true;
                }
            }
            catch (Exception ex)
            {
                GrayParrot.Logging.Logger.For<Publisher<T>>().Error("Errore Publisher", ex);

                throw ex;
            }

            return retValue;
        }

        /// <summary>
        /// Sends the specified message with a delay.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <param name="delay">The delay.</param>
        /// <returns></returns>
        public bool Send(MessageBusBase<T, byte[]> message, DateTime delay)
        {
            bool retValue = false;

            try
            {
                using (GrayParrot.Scheduling.Scheduler m_scheduler = new GrayParrot.Scheduling.Scheduler())
                {
                    m_scheduler.Initialize();
                    m_scheduler.Start(new RunOnceTriggerListener());
                    m_scheduler.Pause();

                    JobParameters m_parameters = new JobParameters(message);
                    m_parameters.Add("subscription", "GrayParrot-Test");

                    m_scheduler.SetSchedule<ScheduledMessage<T>>(delay, m_parameters);

                    m_scheduler.Resume();
                }

                //if (m_client != null)
                //{
                //    if (delay != DateTime.MinValue)
                //    {
                //        message.ScheduledEnqueueTimeUtc = delay.ToUniversalTime();
                //    }


                //    m_client.Send(message);

                //    retValue = true;
                //}
            }
            catch (Exception ex)
            {
                GrayParrot.Logging.Logger.For<Publisher<T>>().Error("Errore Publisher", ex);

                throw ex;
            }

            return retValue;
        }

        #region Disposable...
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        ~Publisher()
        {
            Dispose(false);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (_disposed)
                return;

            if (disposing)
            {
                // free other managed objects that implement
                // IDisposable only
            }

            // release any unmanaged objects
            // set the object references to null

            _disposed = true;
        }
        #endregion
    }
}
